﻿using Assets.Editor.zframe.editor.fonts;
using zframe;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using UnityEditor;
using UnityEngine;
using zframe.json;

namespace zframe.editor
{
    /// <summary>
    /// 位图字体编辑器
    /// </summary>
    public class FontEditorWindow:EditorWindow
    {
        public static void ShowWin()
        {
            FontEditorWindow win = EditorWindow.GetWindow<FontEditorWindow>();
            
        }

        private readonly int DF_ATLAS_SIZE = 256;

        private List<string> _fontImages;
        private List<FontTextureInfo> _fontTexInfos;
        private int _curSize;
        private string _fontSpace = "5";
        Texture2D atlasTex;
        private void Awake()
        {
            int size = 1024;
            maxSize = new Vector2(size, size);
            minSize = new Vector2(256, 256);
            string relativePath = AssetFileUtils.GetSelectFolder();
            string folder = FileUtils.GetDirLastFolderName(relativePath);   
            _fontImages = FileUtils.GetFilesByExts(relativePath, new string[] { ".png" }).Where(f=> Path.GetFileName(f).IndexOf(folder)==-1 ).ToList();
            _fontTexInfos = new List<FontTextureInfo>();
            ReImportImgs();
            _curSize = CalAtlasSize(DF_ATLAS_SIZE);
            ZLogger.Log("Awake _curSize=" + _curSize);
            CreateAltasTex();
        }

        private void ReImportImgs()
        {
            for (int i = 0;i< _fontImages.Count;i++)
            {
                TextureImporter texImport = (TextureImporter)AssetImporter.GetAtPath(_fontImages[i]);

                texImport.isReadable = true;
                texImport.SaveAndReimport();
            }
            AssetDatabase.Refresh();
        }

        private int CalAtlasSize(int curSize)
        {
            int retSize = 0;
            int curW = 0;
            int curH = 0;
            int rowMaxH = 0;
            int rows = 1;
            for (int i = 0; i < _fontImages.Count; i++)
            {
                Texture2D tex = AssetDatabase.LoadAssetAtPath<Texture2D>(_fontImages[i]);
                curW += tex.width + fontSpace;
                if (curW > curSize) //需要换行了
                {
                    curW = tex.width + fontSpace;
                    curH += rowMaxH;
                    rows++;
                }
                else
                {
                    rowMaxH = Math.Max(rowMaxH, tex.height);
                }
                if (curH > curSize)
                {
                    return CalAtlasSize(curSize * 2);
                }

            }
            retSize = curSize;
            ZLogger.Log("CalAtlasSize curSize=" + curSize + ",rows=" + rows);
            return retSize;
            
        }
        
        private void CreateAltasTex()
        {
            if (atlasTex == null)
            {
                atlasTex = new Texture2D(_curSize, _curSize);
            }
            //从左到右、 从下到上排列（即，逐行排列）
            Color32[] colors = new Color32[_curSize*_curSize];
            int idx = 0;
            for (int i = 0; i < _curSize; i++)
            {
                for (int j = 0;j< _curSize;j++)
                {
                    //创建完全透明的
                    colors.SetValue(new Color32(0,0,0,0), idx);
                    idx++;
                }
            }
            atlasTex.SetPixels32(colors);
            atlasTex.Apply();
        }

        /// <summary>
        /// 把小图合并到图集上
        /// </summary>
        private void ClonePixlToAtals()
        {
            int curX = 0;
            int curY = 0;   
            int maxH = 0;
            for (int i = 0; i < _fontImages.Count; i++)
            {
                Texture2D tex = AssetDatabase.LoadAssetAtPath<Texture2D>(_fontImages[i]);
                if (curX + tex.width + fontSpace > _curSize) //换行
                {
                    curX = 0;
                    curY += maxH;
                }
                for (int j = 0; j < tex.width; j++)
                {
                    for (int k = 0; k < tex.height; k++)
                    {
                        SetTexPixel(tex.GetPixel(j, k), curX + j, curY + k);
                    }
                }
                _fontTexInfos[i].url = _fontImages[i];
                _fontTexInfos[i].name = tex.name;
                _fontTexInfos[i].x = curX;
                _fontTexInfos[i].y = curY;  
                maxH = Math.Max(maxH, tex.height);
                curX += tex.width + fontSpace;
                
            }
            atlasTex.Apply();
            
        }

        private void SaveFiles()
        {
            string relativePath = AssetFileUtils.GetSelectFolder();
            if (string.IsNullOrEmpty(relativePath))
            {
                EditorUtility.DisplayDialog("提示","没有选中字体文件夹","确定");
                return;
            }
            if (_fontTexInfos.Count==0 ||_fontImages.Count==0)
            {
                EditorUtility.DisplayDialog("提示", "没有可生成的字体", "确定");
                return;
            }
            string folder = FileUtils.GetDirLastFolderName(relativePath);
            string imaName = GetAtlasName(folder);  
            string absUrl = FileUtils.RelativeToAbsolute(relativePath);
            string url = Path.Combine(absUrl, imaName);
            File.WriteAllBytes(url, atlasTex.EncodeToPNG());
            AssetDatabase.SaveAssets();
            AssetDatabase.Refresh();

            //创建材质
            string matUrl = Path.Combine(relativePath, folder+".mat");
            Material mat = AssetDatabase.LoadAssetAtPath<Material>(matUrl);
            if (mat == null)
            {
                mat = new Material(Shader.Find("UI/Default"));
                AssetDatabase.CreateAsset(mat, matUrl); 
            }
            Texture tex = AssetDatabase.LoadAssetAtPath<Texture>(Path.Combine(relativePath, imaName));
            mat.SetTexture("_MainTex", tex);

            //创建字体
            string fontUrl = Path.Combine(relativePath, folder + ".fontsettings");
            Font font = AssetDatabase.LoadAssetAtPath<Font>(fontUrl);
            bool needCreate = font == null;
            if (needCreate)
            {
                font = new Font();
            }
            var charInfos = GetCharInfo();
            if (charInfos ==null || charInfos.Count==0)
            {
                return;
            }
            font.characterInfo = charInfos.ToArray();   
            font.name = folder;
            font.material = mat;
            if (needCreate)
            {
                AssetDatabase.CreateAsset(font, fontUrl);
            }else
            {
                EditorUtility.SetDirty(font);
            }
                       
            string jsonName = folder + ".json";
            url = Path.Combine(absUrl, jsonName);
            
            UnityJsonList<FontTextureInfo> jsonList = new UnityJsonList<FontTextureInfo>(_fontTexInfos);

            string jsonStr = JsonUtility.ToJson(jsonList, true); //若要序列化数组或原始类型的实际内容，需要将它放入类或结构中。
            File.WriteAllText(url, jsonStr);
           

            AssetDatabase.SaveAssets();
            AssetDatabase.Refresh();

            //无法以.png格式创建tex资源？ 
            //AssetDatabase.CreateAsset(atlasTex, Path.Combine(relativePath, imaName));


        }

        private List<CharacterInfo> GetCharInfo()
        {
            Dictionary<string, bool> dict = new Dictionary<string, bool>();
            List<CharacterInfo> charInfos = new List<CharacterInfo>();
            for (int i = 0; i < _fontTexInfos.Count; i++)
            {
                CharacterInfo charInfo = new CharacterInfo();
                FontTextureInfo texInfo = _fontTexInfos[i];
                if (dict.ContainsKey(texInfo.text))
                {
                    EditorUtility.DisplayDialog("异常提醒","字体存在重复字符","朕知道了");
                    return null;
                }
                charInfo.index = Char.ConvertToUtf32(texInfo.text, 0);
                charInfo.advance = texInfo.width + fontSpace;
                float tx = (float)(texInfo.x) / _curSize;
                float ty = (float)texInfo.y / _curSize;
                float twX = (float)(texInfo.x + texInfo.width + fontSpace) / _curSize;
                float thY = (float)(texInfo.y + texInfo.height) / _curSize;
                charInfo.glyphWidth = texInfo.width;
                charInfo.glyphHeight = texInfo.height;  
                charInfo.uvBottomLeft = new Vector2(tx, ty);
                charInfo.uvBottomRight = new Vector2(twX, ty);
                charInfo.uvTopLeft = new Vector2(tx, thY);
                charInfo.uvTopRight = new Vector2(twX, thY);
                
                //新的API这样设置
                charInfo.minX = 0;
                charInfo.maxX = texInfo.width + fontSpace;
                //图集纹理的左下角是原点[0,0],
                //而Rect左上角是原点[0,0],换算之后 minY = -texInfo.height，maxY = 0
                //要把Rect倒过来截取区域?? 只能这样去理解了
                charInfo.minY = -texInfo.height;  
                charInfo.maxY = 0;

                /*
                 //过时API这样设置
                charInfo.vert = new Rect(0, 0, texInfo.width, -texInfo.height);
                
                ZLogger.Log("GetCharInfo 22 x=" + charInfo.vert.x+",y="+ charInfo.vert.y+ ",xMax=" 
                    + charInfo.vert.xMax+ ",xMin=" + charInfo.vert.xMin+ ",yMin=" + 
                    charInfo.vert.yMin+ ",yMax=" + charInfo.vert.yMax);
                */

                charInfos.Add(charInfo);
            }
            return charInfos;    
        } 
               
        private void SetTexPixel(Color col, int r, int c)
        {
            //从左到右、 从下到上排列（即，逐行排列）
            //左下角开始
            atlasTex.SetPixel(r, c, col);
        }

        private int fontSpace { 
            get {
                return Convert.ToInt32(_fontSpace);
            } 
        }

        private string GetAtlasName(string relativePath)
        {
            string folder = FileUtils.GetDirLastFolderName(relativePath);
            string imaName = folder + ".png";
            return imaName;
        }

        private void OnGUI()
        {
            int imageSize = 25;
            int layoutW = 40;

            titleContent = new GUIContent("创建字体");
            GUILayout.BeginVertical();
            GUILayout.Space(20);

            GUILayout.BeginHorizontal();
            GUILayout.Label("字体间距:", GUILayout.Width(60));
            _fontSpace = GUILayout.TextField(_fontSpace, GUILayout.Width(layoutW));
            GUILayout.EndHorizontal();

            for(int i = 0;i<_fontImages.Count;i++)
            {
                string url = _fontImages[i];
                GUILayout.BeginHorizontal();
                Texture tex = AssetDatabase.LoadAssetAtPath<Texture>(url);
                GUILayout.Label("字体:", GUILayout.Width(layoutW));
                GUILayout.Box(tex, GUILayout.Width(imageSize), GUILayout.Height(imageSize));
                GUILayout.Label("字符:", GUILayout.Width(layoutW));
                string txt;
                if (i<_fontTexInfos.Count)
                {
                    txt = _fontTexInfos[i].text;
                }
                else
                {
                    txt = tex.name;
                    FontTextureInfo texInfo = new FontTextureInfo();
                    texInfo.url = url;
                    texInfo.text = txt;
                    texInfo.width = tex.width;
                    texInfo.height = tex.height;    
                    _fontTexInfos.Add(texInfo);
                }
                _fontTexInfos[i].text = GUILayout.TextField(txt, GUILayout.Width(100),GUILayout.Height(imageSize));
                if (GUILayout.Button("定位",GUILayout.Width(layoutW)))
                {
                    EditorGUIUtility.PingObject(tex);
                }
                if (GUILayout.Button("删除", GUILayout.Width(layoutW)))
                {
                    AssetDatabase.DeleteAsset(_fontImages[i]);
                    _fontImages.RemoveAt(i);
                    _fontTexInfos.RemoveAt(i);
                }
                GUILayout.EndHorizontal();  
            }
            //GUILayout.Box(atlasTex);
            GUILayout.Space(20);
            GUILayout.BeginHorizontal();
            GUILayout.Space(20);
            
            if (GUILayout.Button("生成", GUILayout.Width(60), GUILayout.Height(40)))
            {
                ClonePixlToAtals();
                SaveFiles();
            }
            GUILayout.EndHorizontal();
            GUILayout.EndVertical();
        }

    }
}
